/***
* ==++==
*
* Copyright (c) Microsoft Corporation.  All rights reserved.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* serialization.h
*
* Serialization for blittable types, strings, STL containers, and a few others.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once

#include <tuple>
#include <string>
#include <vector>
#include <queue>
#include <forward_list>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <memory>
#include <hash_map>
#include <hash_set>
#include <unordered_set>
#include <unordered_map>
#include <hash_set>
#include <array>
#include <valarray>
#include <utility>

#include <ostream>

#include "xxpublic.h"

namespace actors
{
    template<typename ReqT, typename RepT> struct reqrep_msg;

    /// <summary>
    /// A block for storing serialized state
    /// </summary>
    struct storage_block
    {
        storage_block() {}
        storage_block(const std::string &type) : Type(type) { }
        storage_block(const std::string &type, const std::vector<byte> &data) : Type(type), Data(data) { }

        storage_block(const storage_block &other) : Type(other.Type), Data(other.Data) { }
        void operator = (const storage_block &other) { Type = other.Type; Data = other.Data; }

        std::string       Type;
        std::vector<byte> Data;
    };

    /// <summary>
    /// Abstract base class for all serializer implementations
    /// </summary>
    class Serializer
    {
    public:
        /// <summary>
        /// Since derived classes may want to destruct properly, this base class needs
        /// a virtual destructor
        /// </summary>
        _ASYNCRTIMP virtual ~Serializer() { }

        /// <summary>
        /// write a number of bytes to the underlying serialization target and 
        /// advance the internal write position.
        /// </summary>
        /// <remarks>
        /// Writing zero bytes always succeeds, whether the underlying buffer, stream, socket, etc. is valid or not
        /// </remarks>
        _ASYNCRTIMP virtual bool write(size_t, const void *) { throw std::exception("Invalid write operation");}

        /// <summary>
        /// read a number of bytes from the underlying serialization source and 
        /// advance the internal read position.
        /// </summary>
        /// <remarks>
        /// reading zero bytes always succeeds, whether the underlying buffer, stream, socket, etc. is valid or not
        /// </remarks>
        _ASYNCRTIMP virtual bool read(size_t, void *) { throw std::exception("Invalid read operation");};

        /// <summary>
        /// Finalize a top-level serialization request
        /// </summary>
        _ASYNCRTIMP virtual bool flush() { return true; }

        /// <summary>
        /// Lock the serializer to avoid concurrent use.
        /// </summary>
        _ASYNCRTIMP virtual void lock() { }

        /// <summary>
        /// Unlock the serializer.
        /// </summary>
        _ASYNCRTIMP virtual void unlock() { }

        /// <summary>
        /// Get a pointer to the first byte of the internal buffer, if there is one.
        /// </summary>
        _ASYNCRTIMP virtual void *Buffer() { return nullptr; }
    };

    /// <summary>
    /// array_serializer allows for efficient serialization into a buffer allocated
    /// by the caller.
    /// </summary>
    class array_serializer : public Serializer
    {
    public:
        _ASYNCRTIMP array_serializer(size_t length, byte *buffer);
        _ASYNCRTIMP array_serializer(size_t length, void *buffer);
        _ASYNCRTIMP array_serializer(storage_block &block);

        /// <summary>
        /// write a number of bytes to the underlying array and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying array and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

        /// <summary>
        /// Get a pointer to the first byte of the underlying array.
        /// </summary>
        _ASYNCRTIMP virtual void *Buffer() { return (char *)m_buffer+m_offset; }

    private:
        size_t m_length, m_offset;
        byte *m_buffer;
    };

    class file_serializer : public Serializer
    {
    public:
        file_serializer(HANDLE hFile) : m_file(hFile) { }

        /// <summary>
        /// write a number of bytes to the underlying file and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying file and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

        /// <summary>
        /// Finalize a top-level serialization request
        /// </summary>
        _ASYNCRTIMP virtual bool flush();

    private:
        HANDLE m_file;
    };

    class stream_serializer : public Serializer
    {
    public:
        stream_serializer(std::iostream &stream) : m_stream(stream) {}

        /// <summary>
        /// write a number of bytes to the underlying stream and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying stream and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

        /// <summary>
        /// Finalize a top-level serialization request
        /// </summary>
        _ASYNCRTIMP virtual bool flush() { m_stream.flush(); return true; }

    private:
        stream_serializer &operator=(const stream_serializer &);
        std::iostream &m_stream;
    };

    class istream_serializer : public Serializer
    {
    public:
        istream_serializer(std::istream &stream) : m_stream(stream) {}

        /// <summary>
        /// write a number of bytes to the underlying stream and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying stream and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

    private:
        istream_serializer &operator=(const istream_serializer &);
        std::istream &m_stream;
    };

    class ostream_serializer : public Serializer
    {
    public:
        ostream_serializer(std::ostream &stream) : m_stream(stream) {}

        /// <summary>
        /// write a number of bytes to the underlying stream and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying stream and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

        /// <summary>
        /// Finalize a top-level serialization request
        /// </summary>
        _ASYNCRTIMP virtual bool flush() { m_stream.flush(); return true; }

    private:
        ostream_serializer &operator=(const ostream_serializer &);
        std::ostream &m_stream;
    };

    class socket_serializer : public Serializer
    {
    public:
        socket_serializer(SOCKET socket) : m_socket(socket) {}

        /// <summary>
        /// write a number of bytes to the underlying socket and 
        /// advance the internal write position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to write</param>
        /// <param name="source">The address of the data block to copy from</param>
        _ASYNCRTIMP virtual bool write(size_t byteCount, const void *source);

        /// <summary>
        /// read a number of bytes from the underlying socket and 
        /// advance the internal read position.
        /// </summary>
        /// <param name="byteCount">The number of bytes to read</param>
        /// <param name="source">The address of the data block to copy to</param>
        _ASYNCRTIMP virtual bool read(size_t byteCount, void *dest);

    private:
        socket_serializer &operator=(const socket_serializer &);
        SOCKET m_socket;
    };

} // namespace actors

//
// Serialization and deserialization of all data is done via three methods:
//
// calculate_size(), which determines the size of the buffer that is necessary
// to serialize the data. Some serializers require that the total size of the data
// to be written is pre-calculated, while others do not require that.
//
// serialize(), which stores the data into a buffer. The pointer passed in points
// at the next available byte, and the implementation is expected to update it
// as it writes data into it. Passed in is also a 'length' argument, which implementations
// are expected to check and update. It holds the number of remaining bytes in the
// allocated buffer, and should be checked to avoid buffer overruns.
//
// deserialize(), which creates an object from a buffer. The pointer passed in points
// to the first byte that remains to be deserialized, and the length field to the
// number of remaining bytes. Implementations are expected to update both. The first
// parameter is a reference to a variable where the deserialized data should be stored.
//

#pragma region "Generic Serialization"
template<typename Payload>
size_t calculate_size(const Payload &)
{
    return sizeof(Payload);
}

template<typename Payload>
bool serialize(const Payload &data, actors::Serializer &serializer)
{
    return serializer.write(sizeof(Payload), (const void *)&data);
}

template<typename Payload>
bool deserialize(Payload &data, actors::Serializer &serializer)
{
    return serializer.read(sizeof(Payload), (void *)&data);
}
#pragma endregion

#pragma region "Non-generic serializers"
_ASYNCRTIMP size_t calculate_size(const char *str);
_ASYNCRTIMP size_t calculate_size(const wchar_t *str);
_ASYNCRTIMP size_t calculate_size(const std::string &str);
_ASYNCRTIMP size_t calculate_size(const std::wstring &str);

_ASYNCRTIMP bool serialize(const char *str, actors::Serializer &serializer);
_ASYNCRTIMP bool serialize(const wchar_t *str, actors::Serializer &serializer);
_ASYNCRTIMP bool serialize(const std::string &str, actors::Serializer &serializer);
_ASYNCRTIMP bool serialize(const std::wstring &str, actors::Serializer &serializer);

_ASYNCRTIMP bool deserialize(const char *&str, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(const wchar_t *&str, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::string &str, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::wstring &str, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const actors::storage_block &msg);
_ASYNCRTIMP bool serialize(const actors::storage_block &msg, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(actors::storage_block &msg, actors::Serializer &serializer);

#pragma endregion


#pragma region "Serialization of Smart Pointers"
template<typename Payload>
size_t calculate_size(const std::shared_ptr<Payload> &data)
{
    return calculate_size(*data);
}

template<typename Payload>
bool serialize(const std::shared_ptr<Payload> &ptr, actors::Serializer &serializer)
{
    const Payload &data = *ptr;
    return serialize(data, serializer);
}

template<typename Payload>
bool deserialize(std::shared_ptr<Payload> &data, actors::Serializer &serializer)
{
    auto pld = std::make_shared<Payload>();

    if ( deserialize(*pld, serializer) )
    {
        data = pld;
        return true;
    }
    return false;
}
#pragma endregion

#pragma region "reqrep_msg"
template<typename ReqT, typename RepT>
size_t calculate_size(const actors::reqrep_msg<ReqT,RepT> &msg)
{
    return calculate_size(msg.reply_to) + calculate_size(msg.data);
}

template<typename ReqT, typename RepT>
bool serialize(const actors::reqrep_msg<ReqT,RepT> &msg, actors::Serializer &serializer)
{
    return serialize(msg.reply_to, serializer) && serialize(msg.data, serializer);
}

template<typename ReqT, typename RepT>
bool deserialize(actors::reqrep_msg<ReqT,RepT> &msg, actors::Serializer &serializer)
{
    return deserialize(msg.reply_to, serializer) && deserialize(msg.data, serializer);
}
#pragma endregion

#pragma region "Pair"
template<typename T1, typename T2>
size_t calculate_size(const std::pair<T1, T2> &data)
{
    size_t s1 = calculate_size(data.first);
    size_t s2 = calculate_size(data.second);
    return s1 + s2;
}

template<typename T1, typename T2>
bool serialize(const std::pair<T1,T2> &data, actors::Serializer &serializer)
{
    return serialize(data.first, serializer) && serialize(data.second, serializer);
}

template<typename T1, typename T2>
bool deserialize(std::pair<T1,T2> &data, actors::Serializer &serializer)
{
    T1 d1;
    T2 d2;

    if (!deserialize(d1, serializer)) return false;
    if (!deserialize(d2, serializer)) return false;

    data = std::make_pair<T1,T2>(d1,d2);

    return true;
}
#pragma endregion

#pragma region "Tuples"
template<typename T1, typename T2>
size_t calculate_size(const std::tuple<T1,T2> &data)
{
    size_t s1 = calculate_size(std::get<0>(data));
    size_t s2 = calculate_size(std::get<1>(data));
    return s1 + s2;
}

template<typename T1, typename T2, typename T3>
size_t calculate_size(const std::tuple<T1,T2,T3> &data)
{
    size_t s1 = calculate_size(std::get<0>(data)); 
    size_t s2 = calculate_size(std::get<1>(data));
    size_t s3 = calculate_size(std::get<2>(data)); 
    return s1 + s2 + s3;
}

template<typename T1, typename T2, typename T3, typename T4>
size_t calculate_size(const std::tuple<T1,T2,T3,T4> &data)
{
    size_t s1 = calculate_size(std::get<0>(data)); 
    size_t s2 = calculate_size(std::get<1>(data));
    size_t s3 = calculate_size(std::get<2>(data)); 
    size_t s4 = calculate_size(std::get<3>(data));
    return s1 + s2 + s3 + s4;
}

template<typename T1, typename T2>
bool serialize(const std::tuple<T1,T2> &data, actors::Serializer &serializer)
{
    if ( !serialize(std::get<0>(data), serializer) ) return false;
    if ( !serialize(std::get<1>(data), serializer) ) return false;
    return true;
}

template<typename T1, typename T2, typename T3>
bool serialize(const std::tuple<T1,T2,T3> &data, actors::Serializer &serializer)
{
    bool r1 = serialize(std::get<0>(data), serializer);
    bool r2 = r1 ? serialize(std::get<1>(data), serializer) : r1;
    bool r3 = r2 ? serialize(std::get<2>(data), serializer) : r2; 
    return r1 && r2 && r3;
}

template<typename T1, typename T2, typename T3, typename T4>
bool serialize(const std::tuple<T1,T2,T3,T4> &data, actors::Serializer &serializer)
{
    bool r1 = serialize(std::get<0>(data), serializer);
    bool r2 = r1 ? serialize(std::get<1>(data), serializer) : r1;
    bool r3 = r2 ? serialize(std::get<2>(data), serializer) : r2; 
    bool r4 = r3 ? serialize(std::get<3>(data), serializer) : r3;
    return r1 && r2 && r3 && r4;
}

template<typename T1, typename T2>
bool deserialize(std::tuple<T1,T2> &data, actors::Serializer &serializer)
{
    T1 d1;
    T2 d2;

    if (!deserialize(d1, serializer)) return false;
    if (!deserialize(d2, serializer)) return false;

    data = std::tie(d1,d2);

    return true;
}

template<typename T1, typename T2, typename T3>
bool deserialize(std::tuple<T1,T2,T3> &data, actors::Serializer &serializer)
{
    T1 d1;
    T2 d2;
    T3 d3;

    if (!deserialize(d1, serializer)) return false;
    if (!deserialize(d2, serializer)) return false;
    if (!deserialize(d3, serializer)) return false;

    data = std::tie(d1,d2,d3);

    return true;
}

template<typename T1, typename T2, typename T3, typename T4>
bool deserialize(std::tuple<T1,T2,T3,T4> &data, actors::Serializer &serializer)
{
    T1 d1;
    T2 d2;
    T3 d3;
    T4 d4;

    if (!deserialize(d1, serializer)) return false;
    if (!deserialize(d2, serializer)) return false;
    if (!deserialize(d3, serializer)) return false;
    if (!deserialize(d4, serializer)) return false;

    data = std::tie(d1,d2,d3,d4);

    return true;
}
#pragma endregion

//
// Note: in the serialization logic for the various collections that follows below
// the size_type of the container is **not** used to serialize the length of the
// container. This is due to the fact that size_t risks being defined differently on
// 32- and 64-bit systems, resulting in incorrect deserialization when moving data
// between a 32-bit client and a 64-bit server (or vice versa). Therefore, we always
// use 64 bits to represent the size of a collection.
//

#pragma region "Vector<T>"
template<typename T>
size_t calculate_size(const std::vector<T> &vector)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = vector.begin(); pos != vector.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::vector<T> &vector, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)vector.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    size_t size = (size_t)serialized_size;

    for (size_t i = 0; i < size; i++)
    {
        if (!serialize(vector[i], serializer)) return false;
    }

    return true;
}

template<typename T>
bool deserialize(std::vector<T> &vector, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    size_t size = (size_t)serialized_size;
    vector.resize(size);

    if ( size == 0 ) return true;

    for (std::vector<T>::size_type i = 0; i < size; i++)
    {
        if (!deserialize(vector[i], serializer)) return false;
    }
    return true;
}

//
// std::vector<T> is very common, and needs specialization for certain common blittable types...
//
_ASYNCRTIMP size_t calculate_size(const std::vector<byte> &vector);
_ASYNCRTIMP bool serialize(const std::vector<byte> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<byte> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<char> &vector);
_ASYNCRTIMP bool serialize(const std::vector<char> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<char> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<short> &vector);
_ASYNCRTIMP bool serialize(const std::vector<short> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<short> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<int> &vector);
_ASYNCRTIMP bool serialize(const std::vector<int> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<int> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<unsigned int> &vector);
_ASYNCRTIMP bool serialize(const std::vector<unsigned int> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<unsigned int> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<long> &vector);
_ASYNCRTIMP bool serialize(const std::vector<long> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<long> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<float> &vector);
_ASYNCRTIMP bool serialize(const std::vector<float> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<float> &vector, actors::Serializer &serializer);

_ASYNCRTIMP size_t calculate_size(const std::vector<double> &vector);
_ASYNCRTIMP bool serialize(const std::vector<double> &vector, actors::Serializer &serializer);
_ASYNCRTIMP bool deserialize(std::vector<double> &vector, actors::Serializer &serializer);

#pragma endregion

#pragma region "Queue<T>"
template<typename T>
size_t calculate_size(const std::queue<T> &queue)
{
    size_t total = sizeof(unsigned __int64);
    std::queue<T> tmp(queue);
    for (std::queue<T>::size_type i = 0; i < queue.size(); i++)
    {
        T item = tmp.front();
        total += calculate_size(item);
        tmp.pop();
    }
    return total;
}

template<typename T>
bool serialize(const std::queue<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)queue.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    size_t size = (size_t)serialized_size;

    std::queue<T> tmp(queue);

    for (size_t i = 0; i < size; i++)
    {
        T item = tmp.front();
        if (!::serialize(item, serializer)) return false;
        tmp.pop();
    }
    return true;
}

template<typename T>
bool deserialize(std::queue<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::queue<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        queue.push(item);
    }
    return true;
}
#pragma endregion

#pragma region "list<T>"
template<typename T>
size_t calculate_size(const std::list<T> &list)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = list.begin(); pos != list.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::list<T> &list, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)list.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = list.begin(); pos != list.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::list<T> &list, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (int i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        list.push_back(item);
    }
    return true;
}
#pragma endregion

#pragma region "priority_queue<T>"
template<typename T>
size_t calculate_size(const std::priority_queue<T> &queue)
{
    size_t total = sizeof(unsigned __int64);
    std::priority_queue<T> tmp(queue);
    for (std::priority_queue<T>::size_type i = 0; i < queue.size(); i++)
    {
        total += calculate_size(tmp.top());
        tmp.pop();
    }
    return total;
}

template<typename T>
bool serialize(const std::priority_queue<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)queue.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    size_t size = (size_t)serialized_size;

    std::priority_queue<T> tmp(queue);

    for (std::priority_queue<T>::size_type i = 0; i < size; i++)
    {
        if (!serialize(tmp.top(), serializer)) return false;
        tmp.pop();
    }
    return true;
}

template<typename T>
bool deserialize(std::priority_queue<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::priority_queue<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        queue.push(item);
    }
    return true;
}
#pragma endregion

#pragma region "Deque<T>"
template<typename T>
size_t calculate_size(const std::deque<T> &queue)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = queue.begin(); pos != queue.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::deque<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)queue.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = queue.begin(); pos != queue.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::deque<T> &queue, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (int i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        queue.push_back(item);
    }
    return true;
}
#pragma endregion

#pragma region "array<T,Size>"
template<typename T, int Size>
size_t calculate_size(const std::array<T,Size> &array)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = array.begin(); pos != array.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T, int Size>
bool serialize(const std::array<T,Size> &array, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)Size;

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = array.begin(); pos != array.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T, int Size>
bool deserialize(std::array<T,Size> &array, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::array<T,Size>::size_type i = 0; i < Size; i++)
    {
        if (!deserialize(array[i], serializer)) return false;
    }
    return true;
}
#pragma endregion

#pragma region "valarray<T>"
template<typename T>
size_t calculate_size(const std::valarray<T> &array)
{
    size_t total = sizeof(unsigned __int64);
    for (int i = 0; i < array.size(); i++)
    {
        total += calculate_size(array[i]);
    }
    return total;
}

template<typename T>
bool serialize(const std::valarray<T> &array, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)array.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    size_t size = (size_t)serialized_size;

    for (size_t i = 0; i < size; i++)
    {
        if (!serialize(array[i], serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::valarray<T> &array, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    new (&array) std::valarray<T>(size);

    for (size_t i = 0; i < count; i++)
    {
        if (!deserialize(array[i], serializer)) return false;
    }
    return true;
}
#pragma endregion

#pragma region "stack<T>"
template<typename T>
size_t calculate_size(const std::stack<T> &stack)
{
    size_t total = sizeof(unsigned __int64);
    auto vector = stack._Get_container();
    for (auto pos = vector.begin(); pos != vector.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::stack<T> &stack, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)stack.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    auto vector = stack._Get_container();
    for (auto pos = vector.begin(); pos != vector.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::stack<T> &stack, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::stack<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        stack.push(item);
    }
    return true;
}
#pragma endregion

#pragma region "set<T>"
template<typename T>
size_t calculate_size(const std::set<T> &set)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::set<T> &set, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)set.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::set<T> &s, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::set<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        s.insert(item);
    }
    return true;
}
#pragma endregion

#pragma region "hash_set<T>"
template<typename T>
size_t calculate_size(const std::hash_set<T> &set)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::hash_set<T> &set, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)set.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::hash_set<T> &set, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::hash_set<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        set.insert(item);
    }
    return true;
}
#pragma endregion

#pragma region "unordered_set<T>"
template<typename T>
size_t calculate_size(const std::unordered_set<T> &set)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        total += calculate_size(*pos);
    }
    return total;
}

template<typename T>
bool serialize(const std::unordered_set<T> &set, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)set.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = set.begin(); pos != set.end(); pos++)
    {
        if (!serialize(*pos, serializer)) return false;
    }
    return true;
}

template<typename T>
bool deserialize(std::unordered_set<T> &s, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::unordered_set<T>::size_type i = 0; i < size; i++)
    {
        T item;
        if (!deserialize(item, serializer)) return false;
        s.insert(item);
    }
    return true;
}
#pragma endregion

#pragma region "map<TKey,TValue>"
template<typename TKey, typename TValue>
size_t calculate_size(const std::map<TKey,TValue> &map)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        total += calculate_size(pos->first);
        total += calculate_size(pos->second);
    }
    return total;
}

template<typename TKey, typename TValue>
bool serialize(const std::map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)map.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        if (!serialize(pos->first, serializer)) return false;
        if (!serialize(pos->second, serializer)) return false;
    }
    return true;
}

template<typename TKey, typename TValue>
bool deserialize(std::map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::map<TKey,TValue>::size_type i = 0; i < size; i++)
    {
        TKey key;
        TValue value;
        if (!deserialize(key, serializer)) return false;
        if (!deserialize(value, serializer)) return false;
        map[key] = value;
    }
    return true;
}
#pragma endregion

#pragma region "hash_map<TKey,TValue>"
template<typename TKey, typename TValue>
size_t calculate_size(const std::hash_map<TKey,TValue> &map)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        total += calculate_size(pos->first);
        total += calculate_size(pos->second);
    }
    return total;
}

template<typename TKey, typename TValue>
bool serialize(const std::hash_map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)map.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        if (!serialize(pos->first, serializer)) return false;
        if (!serialize(pos->second, serializer)) return false;
    }
    return true;
}

template<typename TKey, typename TValue>
bool deserialize(std::hash_map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::hash_map<TKey,TValue>::size_type i = 0; i < size; i++)
    {
        TKey key;
        TValue value;
        if (!deserialize(key, serializer)) return false;
        if (!deserialize(value, serializer)) return false;
        map[key] = value;
    }
    return true;
}
#pragma endregion

#pragma region "unordered_map<TKey,TValue>"
template<typename TKey, typename TValue>
size_t calculate_size(const std::unordered_map<TKey,TValue> &map)
{
    size_t total = sizeof(unsigned __int64);
    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        total += calculate_size(pos->first);
        total += calculate_size(pos->second);
    }
    return total;
}

template<typename TKey, typename TValue>
bool serialize(const std::unordered_map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size = (unsigned __int64)map.size();

    if ( !serializer.write(sizeof(serialized_size), &serialized_size) ) return false;

    for (auto pos = map.begin(); pos != map.end(); pos++)
    {
        if (!serialize(pos->first, serializer)) return false;
        if (!serialize(pos->second, serializer)) return false;
    }
    return true;
}

template<typename TKey, typename TValue>
bool deserialize(std::unordered_map<TKey,TValue> &map, actors::Serializer &serializer)
{
    unsigned __int64 serialized_size;

    if ( !serializer.read(sizeof(serialized_size), &serialized_size) ) return false;

    if ( serialized_size == 0 ) return true;

    size_t size = (size_t)serialized_size;

    for (std::unordered_map<TKey,TValue>::size_type i = 0; i < size; i++)
    {
        TKey key;
        TValue value;
        if (!deserialize(key, serializer)) return false;
        if (!deserialize(value, serializer)) return false;
        map[key] = value;
    }
    return true;
}
#pragma endregion


template<typename T>
bool Encode(std::vector<byte> &target, const T &input)
{
    target.resize(calculate_size(input));

    actors::array_serializer serializer(target.size(), &target[0]);

    return serialize(input, serializer);
}

template<typename T>
bool Extract(const std::vector<byte> &input, T &result)
{
    std::vector<byte> &data = const_cast<std::vector<byte> &>(input);

    actors::array_serializer serializer(data.size(), &data[0]);

    return deserialize(result, serializer);
}

inline bool Extract(const std::vector<byte> &input, std::string &result)
{
    if ( input.size() == 0 )
    {
        result = "";
        return false;
    }
    else
    {
        std::vector<byte> &data = const_cast<std::vector<byte> &>(input);
        size_t length = data.size()-1;  // Compensate for the null-terminator.
        result.resize(length);
        if ( result.size() > 0 )
            memcpy(&result[0], &data[0], length);
        return true;
    }
}

inline bool Extract(const std::vector<byte> &input, std::wstring &result)
{
    if ( input.size() == 0 )
    {
        result = L"";
        return false;
    }
    else
    {
        std::vector<byte> &data = const_cast<std::vector<byte> &>(input);
        size_t length = data.size() / sizeof(wchar_t) - 1;  // Compensate for the null-terminator.
        result.resize(length);
        if ( result.size() > 0 )
            memcpy(&result[0], &data[0], length*sizeof(wchar_t));
        return true;
    }
}
